package org.teammach.laddercomp.dao;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.Hashtable;
import java.util.List;
import java.util.StringTokenizer;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;

import org.teammach.laddercomp.shared.BlogEntry;
import org.teammach.laddercomp.shared.Ladder;
import org.teammach.laddercomp.shared.OfficialLadder;
import org.teammach.laddercomp.shared.RoundLadder;
import org.teammach.laddercomp.shared.Team;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;

public enum LadderManager {
	INSTANCE;

	public List<Ladder> listLadders() {
		// DatastoreService datastore = DatastoreServiceFactory
		// .getDatastoreService();
		// add();
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Query query = pm.newQuery(Ladder.class);
		query.setOrdering("currentScore desc");

		// List<Entity> ladders = datastore.prepare(query).asList(
		// FetchOptions.Builder.withLimit(50));

		// EntityManager em = EMFService.get().createEntityManager();
		// Read the existing entries
		// Query q = em.createQuery("select m from Ladder m");
		// List<Ladder> ladders = q.getResultList();
		// List<Ladder> ladders = new ArrayList<Ladder>();
		// ladders.add(new Ladder("Dave", "The best", null));
		// clear();
		// add();
		// addTeams();
		List<Ladder> ladders = (List<Ladder>) query.execute();
		System.out.println("Found " + ladders.size() + " ladders");
		// pm.deletePersistentAll(ladders);
		pm.close();
		return ladders;
		// return new ArrayList<Ladder>();
	}

	public void updateOfficial() {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Query query = pm.newQuery(Ladder.class);
		query.setFilter("user == username");
		query.declareParameters("String username");
		List<Ladder> ladders = (List<Ladder>) query.execute("Official");
		if (ladders.size() == 0)
			return;
		Ladder ladder = ladders.get(0);
		// parseTeams();
		ladder.setTeams(parseTeamnames());
		pm.makePersistent(ladder);
		pm.close();

	}
	
	public void updateOfficial2() {
		
		updateTeams();
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Query query = pm.newQuery(OfficialLadder.class);
		
		query.deletePersistentAll();
		OfficialLadder offi = new OfficialLadder(-1, null);
		
		offi.setUpdated(new Date());
		pm.makePersistent(offi);
		pm.close();
		
	}
	
	public OfficialLadder getLatestOfficial() {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Query query = pm.newQuery(OfficialLadder.class);
		query.setFilter("round == offRound");
		query.declareParameters("Integer offRound");
		query.setOrdering("updated desc");
		query.setRange("0,1");
		List<OfficialLadder> ladders = (List<OfficialLadder>) query.execute(-1);
		System.out.println("Returning team last updated at " + ladders.get(0).getUpdated());
		return ladders.get(0);
	}
	
	public RoundLadder getRoundLadder(int round) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Query query = pm.newQuery(RoundLadder.class);
		query.setFilter("round == parRound");
		query.declareParameters("Integer parRound");

		List<RoundLadder> ladders = (List<RoundLadder>) query.execute(round);
		if(ladders.size() == 0) {
			String[] teamNames = new String[] {
					"Adelaide", "Collingwood", "Essendon", "Fremantle",
					"Gold Coast", "Carlton", "Hawthorn", "Melbourne", "Brisbane",
					"Geelong", "North Melbourne", "Port Adelaide", "Richmond",
					"St Kilda", "Sydney", "West Coast", "Western Bulldogs" };
			ArrayList<String> teams = new ArrayList<String>();
			for(String s : teamNames) {
				teams.add(s);
			}
			RoundLadder ladder = new RoundLadder(round, teams);
			
			pm.close();
			return ladder;
			
		}else {
			System.out.println("Returning existing ladder from db");
			pm.close();
			return ladders.get(0);
		}
	}
	
	public void updateRoundLadder(RoundLadder roundLadder) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		pm.makePersistent(roundLadder);
		
		List<Ladder> ladders = listLadders();
		for(Ladder ladder : ladders) {
			
			ladder.setScoreForPrevious(roundLadder.getRound(), roundLadder.getValid()? calcScore(ladder.getTeams(), roundLadder.getTeams()) : -101);
			pm.makePersistent(ladder);
		}
		
		pm.close();
	}
	
	public List<Team> getTeams() {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Query query = pm.newQuery(Team.class);
		query.setOrdering("curPos asc");
		List<Team> allTeams = (List<Team>) query.execute();
		return allTeams;
	}

	public Ladder getLadder(String user) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Query query = pm.newQuery(Ladder.class);
		query.setFilter("user == username");
		query.declareParameters("String username");
		List<Ladder> ladders = (List<Ladder>) query.execute(user);
		if (ladders.size() == 0)
			return null;
		pm.close();
		return ladders.get(0);
	}

	public void clearAll() {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Query query = pm.newQuery(Ladder.class);
		List<Ladder> ladders = (List<Ladder>) query.execute();
		System.out.println("Found " + ladders.size() + " ladders");
		pm.deletePersistentAll(ladders);
		query = pm.newQuery(Team.class);
		query.deletePersistentAll();
//		query = pm.newQuery(BlogEntry.class);
//		query.deletePersistentAll();
		query= pm.newQuery(RoundLadder.class);
		query.deletePersistentAll();
		pm.close();
	}

	public void addAll() {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		// pm.makePersistent(createLadder("Dave", "Awesome", new String[] {
		// "Adelaide", "Brisbane", "Carlton", "Collingwood", "Essendon",
		// "Fremantle", "Geelong", "Gold Coast", "Hawthorn", "Melbourne",
		// "North Melbourne", "Richmond", "St Kilda",
		// "Sydney", "West Coast", "Western Bulldogs" , "Port Adelaide"}));
		//
		// pm.makePersistent(createLadder("Jac", "Not so awesome", new String[]
		// {
		// "Adelaide", "Collingwood", "Essendon", "Fremantle",
		// "Gold Coast", "Carlton", "Hawthorn", "Melbourne", "Brisbane",
		// "Geelong", "North Melbourne", "Port Adelaide", "Richmond",
		// "St Kilda", "Sydney", "West Coast", "Western Bulldogs" }));
		// pm.makePersistent(createLadder("Geoff", "Not so awesome", new
		// String[] {
		// "Adelaide", "Collingwood", "Essendon", "Fremantle",
		// "Gold Coast", "Carlton", "Hawthorn", "Melbourne", "Brisbane",
		// "Geelong", "North Melbourne", "Port Adelaide", "Richmond",
		// "St Kilda", "Sydney", "West Coast", "Western Bulldogs" }));
		// pm.makePersistent(createLadder("Cam", "Not so awesome", new String[]
		// {
		// "Adelaide", "Collingwood", "Essendon", "Fremantle",
		// "Gold Coast", "Carlton", "Hawthorn", "Melbourne", "Brisbane",
		// "Geelong", "North Melbourne", "Port Adelaide", "Richmond",
		// "St Kilda", "Sydney", "West Coast", "Western Bulldogs" }));
		// pm.makePersistent(createLadder("Pat", "Not so awesome", new String[]
		// {
		// "Adelaide", "Collingwood", "Essendon", "Fremantle",
		// "Gold Coast", "Carlton", "Hawthorn", "Melbourne", "Brisbane",
		// "Geelong", "North Melbourne", "Port Adelaide", "Richmond",
		// "St Kilda", "Sydney", "West Coast", "Western Bulldogs" }));
		// pm.makePersistent(createLadder("Haydn", "Not so awesome", new
		// String[] {
		// "Adelaide", "Collingwood", "Essendon", "Fremantle",
		// "Gold Coast", "Carlton", "Hawthorn", "Melbourne", "Brisbane",
		// "Geelong", "North Melbourne", "Port Adelaide", "Richmond",
		// "St Kilda", "Sydney", "West Coast", "Western Bulldogs" }));
		pm.makePersistent(createLadder("Official", "Official", new String[] {
				"Adelaide", "Collingwood", "Essendon", "Fremantle",
				"Gold Coast", "GWS", "Carlton", "Hawthorn", "Melbourne", "Brisbane",
				"Geelong", "North Melbourne", "Port Adelaide", "Richmond",
				"St Kilda", "Sydney", "West Coast", "Western Bulldogs" }));

		// DatastoreService datastore = DatastoreServiceFactory
		// .getDatastoreService();
		//
		// Entity ladder = new Entity("Ladder");
		// ladder.setProperty("User", "Dave ");
		// ladder.setProperty("CurrentScore", 3 + (int) (Math.random() * 100));
		// ladder.setProperty("Commentary", "Doing brilliantly");
		// datastore.put(ladder);

		pm.close();
		// synchronized (this) {
		// EntityManager em = EMFService.get().createEntityManager();
		// Ladder ladder = new Ladder(userId, commentary, teams);
		// em.persist(ladder);
		// em.close();
		// }
	}

	public void updateScores() {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Ladder official = getLadder("Official");
		Query query = pm.newQuery(Ladder.class);
		List<Ladder> ladders = (List<Ladder>) query.execute();

		for (Ladder l : ladders) {

			List<String> teams = l.getTeams();
			int total = 0;
			boolean topEight = true;
			for (int i = 0; i < teams.size(); i++) {
				int predicted = i + 1;
				int actual = official.getTeams().indexOf(teams.get(i)) + 1;
				if(actual == 0) {
					System.out.println("ERROR: " + l.getUser() + " : " + teams.get(i));
				}
				int difference = Math.abs(actual - predicted);
				
				total += (5 - difference);
				if (topEight && i < 8) {
					if (actual > 8)
						topEight = false;
				}
			}
			if (teams.get(0).equalsIgnoreCase(official.getTeams().get(0))) {
				total += 5;
			}
			if (teams.get(teams.size() - 1).equalsIgnoreCase(
					official.getTeams().get(teams.size() - 1))) {
				total += 5;
			}
			if (topEight) {
				total += 5;
			}

			l.setCurrentScore(total);
			pm.makePersistent(l);
		}
		pm.close();

	}

	public void addTeams() {
		PersistenceManager pm = PMF.get().getPersistenceManager();

		DatastoreService datastore = DatastoreServiceFactory
				.getDatastoreService();
		String teams[] = new String[] { "Adelaide", "Brisbane", "Carlton",
				"Collingwood", "Essendon", "Fremantle", "Geelong",
				"Gold Coast", "GWS", "Hawthorn", "Melbourne", "North Melbourne",
				"Port Adelaide", "Richmond", "St Kilda", "Sydney",
				"West Coast", "Western Bulldogs" };
		int i = 1;
		for (String team : teams) {
			Entity teamEntity = new Entity("Team", team);

			teamEntity.setProperty("Team name", team);

			teamEntity.setProperty("Current Position", i++);
			datastore.put(teamEntity);
		}

	}

	public void addLaddersFromCSV(String filename) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try {
			BufferedReader reader = new BufferedReader(new FileReader(new File(
					filename)));
			String line = reader.readLine();
			while (line != null) {
				StringTokenizer st = new StringTokenizer(line, ",");
				String teamName = st.nextToken();
				String commentary = st.nextToken();
				ArrayList<String> teams = new ArrayList<String>();
				while (st.hasMoreTokens()) {
					teams.add(st.nextToken());
				}
				pm.makePersistent(new Ladder(teamName, commentary, teams));

				line = reader.readLine();
			}

		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			pm.close();
		}

	}

	private Ladder createLadder(String userName, String commentary,
			String[] teams) {
		ArrayList<String> list = new ArrayList<String>();
		for (String team : teams) {
			list.add(team);
		}
		return new Ladder(userName, commentary, list);
	}

	public void updateCommentary(String user, String commentary) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Query query = pm.newQuery(Ladder.class);
		query.setFilter("user == username");
		query.declareParameters("String username");
		List<Ladder> ladders = (List<Ladder>) query.execute(user);
		if (ladders.size() == 0)
			return;

		Ladder ladder = ladders.get(0);
		ladder.setCommentary(commentary);
		pm.makePersistent(ladder);
		pm.close();

	}

	public void updateTeams() {

		PersistenceManager pm = PMF.get().getPersistenceManager();
		Query query = pm.newQuery(Team.class);
		List<Team> allTeams = (List<Team>) query.execute();

		
		Hashtable<String, String> nameMap = new Hashtable<String, String>();
		nameMap.put("Geelong Cats", "Geelong");
		nameMap.put("West Coast Eagles", "West Coast");
		nameMap.put("Sydney Swans", "Sydney");
		nameMap.put("Adelaide Crows", "Adelaide");
		nameMap.put("St. Kilda", "St Kilda");
		nameMap.put("Gold Coast Suns", "Gold Coast");
		nameMap.put("Geelong Cats", "Geelong");
		nameMap.put("Brisbane Lions", "Brisbane");
		nameMap.put("GWS Giants", "GWS");

		System.out.println("Parsing teams...");
		try {
			URL url = new URL(
					"http://superstats.heraldsun.com.au/ss2/ladders/ladder-lot-2012.html");
			BufferedReader reader = new BufferedReader(new InputStreamReader(
					url.openStream()));
			String line;
			boolean first = true;
			int colsRead = -1;
			Team curTeam = null;
			int teamsRead = 1;
			while ((line = reader.readLine()) != null) {
				if (line.contains("<td class=\"team")) {
					if (first) {
						first = false;
					} else {
						String teamName = line.substring(line.indexOf('>') + 1,
								line.indexOf('/') - 1);
						if (nameMap.containsKey(teamName)) {
							curTeam = findTeam(nameMap.get(teamName), allTeams);

						} else {
							curTeam = findTeam(teamName, allTeams);

						}
						curTeam.setCurPos(teamsRead++);
						colsRead = 0;

					}
				} else if (!first && colsRead != -1) {
					colsRead++;
					switch (colsRead) {
					case 1:
						curTeam.setPlayed(Integer.parseInt(line.substring(line
								.indexOf('>') + 1, line.indexOf('/') - 1)));
						break;
					case 2:
						curTeam.setWon(Integer.parseInt(line.substring(line
								.indexOf('>') + 1, line.indexOf('/') - 1)));
						break;
					case 3:
						curTeam.setLost(Integer.parseInt(line.substring(line
								.indexOf('>') + 1, line.indexOf('/') - 1)));
						break;
					case 4:
						curTeam.setDrawn(Integer.parseInt(line.substring(line
								.indexOf('>') + 1, line.indexOf('/') - 1)));
						break;
					case 8:
						curTeam.setPoints(Integer.parseInt(line.substring(line
								.indexOf('>') + 1, line.indexOf('/') - 1)));
						colsRead = -1;
						System.out.println("Read team " + curTeam.getTeamName() + " with " + curTeam.getWon() + " wins");

						pm.makePersistent(curTeam);
						break;
					}
				}

				// ...
			}
			System.out.println("Finished");
			reader.close();

		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		pm.close();
	}

	public List<String> parseTeamnames() {

		Hashtable<String, String> nameMap = new Hashtable<String, String>();
		nameMap.put("Geelong Cats", "Geelong");
		nameMap.put("West Coast Eagles", "West Coast");
		nameMap.put("Sydney Swans", "Sydney");
		nameMap.put("Adelaide Crows", "Adelaide");
		nameMap.put("St. Kilda", "St Kilda");
		nameMap.put("Gold Coast Suns", "Gold Coast");
		nameMap.put("Geelong Cats", "Geelong");
		nameMap.put("Brisbane Lions", "Brisbane");
		nameMap.put("GWS Giants", "GWS");

		ArrayList<String> teamNames = new ArrayList<String>();
		ArrayList<Team> teams = new ArrayList<Team>();
		System.out.println("Parsing teams...");
		try {
//			System.setProperty("http.proxyHost", "bproxy.its.rmit.edu.au");
//			System.setProperty("http.proxyPort", "8080");
//			System.setProperty("http.proxyUser", "e71034");
//			System.setProperty("http.proxyPassword", "Banaue!204");
			URL url = new URL(
					"http://superstats.heraldsun.com.au/ss2/ladders/ladder-lot-2012.html");
			BufferedReader reader = new BufferedReader(new InputStreamReader(
					url.openStream()));
			String line;
			boolean first = true;
			int colsRead = -1;
			Team curTeam = null;
			while ((line = reader.readLine()) != null) {
				if (line.contains("<td class=\"team")) {
					if (first) {
						first = false;
					} else {
						String teamName = line.substring(line.indexOf('>') + 1,
								line.indexOf('/') - 1);
						if (nameMap.containsKey(teamName)) {
							teamNames.add(nameMap.get(teamName));
							curTeam = new Team(nameMap.get(teamName));

						} else {
							teamNames.add(teamName);
							curTeam = new Team(teamName);

						}
						colsRead = 0;

					}
				} else if (!first && colsRead != -1) {
					colsRead++;
					switch (colsRead) {
					case 1:
						curTeam.setPlayed(Integer.parseInt(line.substring(line
								.indexOf('>') + 1, line.indexOf('/') - 1)));
						break;
					case 2:
						curTeam.setWon(Integer.parseInt(line.substring(line
								.indexOf('>') + 1, line.indexOf('/') - 1)));
						break;
					case 3:
						curTeam.setLost(Integer.parseInt(line.substring(line
								.indexOf('>') + 1, line.indexOf('/') - 1)));
						break;
					case 4:
						curTeam.setDrawn(Integer.parseInt(line.substring(line
								.indexOf('>') + 1, line.indexOf('/') - 1)));
						break;
					case 8:
						curTeam.setPoints(Integer.parseInt(line.substring(line
								.indexOf('>') + 1, line.indexOf('/') - 1)));
						colsRead = -1;
						System.out.println("ParseTeamnames : Read team " + curTeam.getTeamName() + " with " + curTeam.getWon() + " wins");

						curTeam = null;
						teams.add(curTeam);
						break;
					}
				}

				// ...
			}
			System.out.println("Finished");
			reader.close();

		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

		return teamNames;
	}
	
	
	public int calcScore(List<String> teamsA, List<String> teamsB) {
		int total = 0;
		boolean topEight = true;
		for (int i = 0; i < teamsA.size(); i++) {
			int predicted = i + 1;
			int actual = teamsB.indexOf(teamsA.get(i)) + 1;
			int difference = Math.abs(actual - predicted);
			total += (5 - difference);
			if (topEight && i < 8) {
				if (actual > 8)
					topEight = false;
			}
		}
		if (teamsA.get(0).equalsIgnoreCase(teamsB.get(0))) {
			total += 5;
		}
		if (teamsA.get(teamsA.size() - 1).equalsIgnoreCase(
				teamsB.get(teamsA.size() - 1))) {
			total += 5;
		}
		if (topEight) {
			total += 5;
		}
		return total;

	}
	
	private Team findTeam(String teamName, List<Team>teams) {
		
		for(Team team : teams) {
			if(team.getTeamName().equalsIgnoreCase(teamName)) {
				return team;
			}
		}
		return new Team(teamName);
	}
	
	public static String getOrdinalFor(int value) {
		int hundredRemainder = value % 100;
		int tenRemainder = value % 10;
		if (hundredRemainder - tenRemainder == 10) {
			return "th";
		}

		switch (tenRemainder) {
		case 1:
			return "st";
		case 2:
			return "nd";
		case 3:
			return "rd";
		default:
			return "th";
		}
	}

}
